package util

import (
	"crypto/md5"
	"encoding/hex"
	"gitee.com/chunanyong/zorm"
	"github.com/gin-gonic/gin"
	"gopkg.in/yaml.v3"
	"log"
	"net/http"
	"os"
	"sync"
)

// Config 定义一个结构体，用于表示YAML文件中的数据结构
type Config struct {
	Database0        Database   `yaml:"database0"`
	Database1        Database   `yaml:"database1"`
	Database2        Database   `yaml:"database2"`
	OriginalApisHost string     `yaml:"originalApisHost"`
	Server           Server     `yaml:"server"`
	TaskConfig       TaskConfig `yaml:"scheduleTask"`
	RetryTime        int        `yaml:"retryTime"`
}
type Database struct {
	DSN        string `yaml:"DSN"`
	DriverName string `yaml:"DriverName"`
	Dialect    string `yaml:"Dialect"`
}
type Server struct {
	Port     string `yaml:"port"`
	LogLevel string `yaml:"logLevel"`
}
type TaskConfig struct {
	Enable bool   `yaml:"enable"`
	Cron   string `yaml:"cron"`
}

func ReadConfig() (*zorm.DataSourceConfig, *zorm.DataSourceConfig, *zorm.DataSourceConfig, *Server, *TaskConfig, error) {
	// 读取YAML文件
	yamlFile, err := os.ReadFile("conf/config.yml")
	if err != nil {
		log.Fatalf("无法读取YAML文件: %v", err)
	}
	var config Config
	// 解析YAML文件
	err = yaml.Unmarshal(yamlFile, &config)
	if err != nil {
		log.Fatalf("无法解析YAML文件: %v", err)
		return nil, nil, nil, nil, nil, err
	}
	MainCtx.OriginalApisHost = config.OriginalApisHost
	MainCtx.RetryTime = config.RetryTime
	dbConfig0 := &zorm.DataSourceConfig{
		//DSN 数据库的连接字符串,parseTime=true会自动转换为time格式,默认查询出来的是[]byte数组.&loc=Local用于设置时区
		DSN: config.Database0.DSN,
		//sql.Open(DriverName,DSN) DriverName就是驱动的sql.Open第一个字符串参数,根据驱动实际情况获取
		DriverName:            config.Database0.DriverName, //数据库驱动名称
		Dialect:               config.Database0.Dialect,    //数据库类型
		SlowSQLMillis:         0,                           //慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		MaxOpenConns:          0,                           //数据库最大连接数,默认50
		MaxIdleConns:          0,                           //数据库最大空闲连接数,默认50
		ConnMaxLifetimeSecond: 0,                           //连接存活秒时间. 默认600(10分钟)后连接被销毁重建.
		//避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		DefaultTxOptions: nil, //事务隔离级别的默认配置,默认为nil
	}
	dbConfig1 := &zorm.DataSourceConfig{
		//DSN 数据库的连接字符串,parseTime=true会自动转换为time格式,默认查询出来的是[]byte数组.&loc=Local用于设置时区
		DSN: config.Database1.DSN,
		//sql.Open(DriverName,DSN) DriverName就是驱动的sql.Open第一个字符串参数,根据驱动实际情况获取
		DriverName:            config.Database1.DriverName, //数据库驱动名称
		Dialect:               config.Database1.Dialect,    //数据库类型
		SlowSQLMillis:         0,                           //慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		MaxOpenConns:          0,                           //数据库最大连接数,默认50
		MaxIdleConns:          0,                           //数据库最大空闲连接数,默认50
		ConnMaxLifetimeSecond: 0,                           //连接存活秒时间. 默认600(10分钟)后连接被销毁重建.
		//避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		DefaultTxOptions: nil, //事务隔离级别的默认配置,默认为nil
	}
	dbConfig2 := &zorm.DataSourceConfig{
		//DSN 数据库的连接字符串,parseTime=true会自动转换为time格式,默认查询出来的是[]byte数组.&loc=Local用于设置时区
		DSN: config.Database2.DSN,
		//sql.Open(DriverName,DSN) DriverName就是驱动的sql.Open第一个字符串参数,根据驱动实际情况获取
		DriverName:            config.Database2.DriverName, //数据库驱动名称
		Dialect:               config.Database2.Dialect,    //数据库类型
		SlowSQLMillis:         0,                           //慢sql的时间阈值,单位毫秒.小于0是禁用SQL语句输出;等于0是只输出SQL语句,不计算执行时间;大于0是计算SQL执行时间,并且>=SlowSQLMillis值
		MaxOpenConns:          0,                           //数据库最大连接数,默认50
		MaxIdleConns:          0,                           //数据库最大空闲连接数,默认50
		ConnMaxLifetimeSecond: 0,                           //连接存活秒时间. 默认600(10分钟)后连接被销毁重建.
		//避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
		DefaultTxOptions: nil, //事务隔离级别的默认配置,默认为nil
	}
	server := &Server{
		Port:     config.Server.Port,
		LogLevel: config.Server.LogLevel,
	}
	taskConfig := &TaskConfig{
		Enable: config.TaskConfig.Enable,
		Cron:   config.TaskConfig.Cron,
	}
	return dbConfig0, dbConfig1, dbConfig2, server, taskConfig, nil
}

// Md5Encrypt 返回输入字符串的MD5哈希值的16进制表示
func Md5Encrypt(text string) string {
	// 创建一个新的哈希接口实例
	hasher := md5.New()

	// 写入需要加密的数据
	hasher.Write([]byte(text))

	// 计算哈希值，返回的是一个字节切片
	hashBytes := hasher.Sum(nil)

	// 将字节切片转换为16进制的字符串
	return hex.EncodeToString(hashBytes)
}

// LoginRequired 登录拦截中间件
func LoginRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 从请求中获取用户凭证（例如，从请求头、Cookie、Session等中获取）
		// 这里仅作为示例，假设从请求头中获取用户名和密码
		token := c.Request.Header.Get("Authorization")

		// 验证用户凭证
		if MainCtx.Sessions.GetLoginUser(token) == nil {
			// 验证失败，返回未授权的错误响应
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未授权"})
			return
		}

		// 验证成功，继续执行下一个中间件或处理函数
		c.Next()
	}
}

type SafeMap struct {
	mu sync.Mutex
	m  map[string]any
}

func NewSafeMap() *SafeMap {
	return &SafeMap{
		m: make(map[string]any),
	}
}

func (sm *SafeMap) Get(key string) any {
	sm.mu.Lock()
	defer sm.mu.Unlock()
	return sm.m[key]
}

func (sm *SafeMap) Store(key string, value any) {
	sm.mu.Lock()
	defer sm.mu.Unlock()
	sm.m[key] = value
}

func (sm *SafeMap) GetMap() map[string]any {
	return sm.m
}
